﻿using System;
using System.Collections.Generic;
using Nvigorate.Aspect;
using Nvigorate.Data.Query;
using Nvigorate.Relational.Mapping.Fluent;
using Nvigorate.Relational.State;

namespace Nvigorate.TestObjects
{
    public enum PersonGender
    {
        Undefined,
        Male,
        Female
    }

    public class EmployeeDTO
    {
        public string FullName { get; set; }
        public string DepartmentName { get; set; }
        public string DepartmentDescription { get; set; }
        public string JobTitle { get; set; }
        public string JobDescription { get; set; }
    }

    //[DatabaseLazyLoadAspect(RepositoryName = "simple")]
    [StateTrackingAspect]
    public class Employee : Person
    {
        protected string _test = "";
        private Employee _manager;
        private Department _department;

        public long Id
        { get; set; }
        
        public IList<Employee> Employees { get; set; }

        public Department Department {
            get
            {
                return _department;    
            } 
            set
            {
                if (_department != null && _department.Employees != null && _department.Employees.Contains(this))
                    _department.Employees.Remove(this);

                _department = value;

                if (_department != null && _department.Employees != null && !_department.Employees.Contains(this))
                    _department.Employees.Add(this);
            }
        }

        public Job JobTitle { get; set; }

        public Employee Manager 
        { 
            get
            {
                return _manager;
            }
            set
            {
                if (_manager != null && _manager.Employees != null && _manager.Employees.Contains(this))
                    _manager.Employees.Remove(this);

                _manager = value;

                if(_manager != null && _manager.Employees != null && !value.Employees.Contains(this))
                    value.Employees.Add(this);
            } 
        }

        public Employee()
        {
            Employees = new List<Employee>();
        }
    }

    public class EmployeeMap : FluentMap<Employee>
    {
        public EmployeeMap()
        {
            var personMap = new PersonMap();
            var parentTable = personMap["Person"];

            RepositoryName = "simple";

            var employee = MapTable<DatabaseSchema.nvigorate.employeeSchema>();

            employee.Assign(e => e.Id, t => t.EmployeeId).AsKey().ReadOnly();
            employee.Assign(e => e.Department.Id, t => t.DepartmentId);
            employee.Assign(e => e.JobTitle.Id, t => t.JobTitleId);
            employee.Assign(e => e.Manager.Id, t => t.ManagerId);
            employee.Assign(e => e.SocialSecurity, t => t.EmployeeSocial);

            employee.JoinFromInherited(
                    parentTable,
                    JoinType.Left, 
                    employee.PropertyCriteria(e => e.SocialSecurity)
                        .EqualTo(parentTable.Property(p => p.SocialSecurity))
                );

            MapChildren(e => e.Employees)
                .ForeignKey(e => e.Id, e => e.Manager.Id);

            MapParent(e => e.Manager)
                .ForeignKey(e => e.Manager.Id, e => e.Id);

            MapParent(e => e.Department)
                .ForeignKey(e => e.Department.Id, d => d.Id);

            MapParent(e => e.JobTitle)
                .ForeignKey(e => e.JobTitle.Id, j => j.Id);
        }
    }

    //[DatabaseLazyLoadAspect(RepositoryName = "simple")]
    [StateTrackingAspect]
    public class Department : StateTracking
    {
        public long Id { get; set; }
        public string Name { get; set; }

        public Employee Manager { get; set; }
        public List<Employee> Employees { get; set; }

        public Department()
        {
            Employees = new List<Employee>();
        }
    }

    public class DepartmentMap : FluentMap<Department>
    {
        public DepartmentMap()
        {
            RepositoryName = "simple";

            var department = MapTable();

            department.Assign(d => d.Id).AsKey().ReadOnly().ToColumn("DepartmentId");
            department.Assign(d => d.Name).ToColumn("DepartmentName");
            department.Assign(d => d.Manager.Id).ToColumn("ManagerId");

            MapChild(d => d.Manager)
                .ForeignKey(d => d.Manager.Id, e => e.Id);

            MapChildren(d => d.Employees)
                .ForeignKey(d => d.Id, e => e.Department.Id);
        }
    }

    //[DatabaseLazyLoadAspect(RepositoryName = "simple")]
    [StateTrackingAspect]
    public class Job : StateTracking
    {
        public long Id { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public decimal MinimumPay { get; set; }
        public decimal MaximumPay { get; set; }
    }

    public class JobMap : FluentMap<Job>
    {
        public JobMap()
        {
            RepositoryName = "simple";

            var job = MapTable("JobTitle");

            job.Assign(j => j.Id).AsKey().ReadOnly().ToColumn("JobTitleId");
            job.Assign(j => j.Title).ToColumn("JobTitle");
            job.Assign(j => j.Description).ToColumn("JobDescription");
            job.Assign(j => j.MaximumPay).ToColumn("MaxPay");
            job.Assign(j => j.MinimumPay).ToColumn("MinPay");
        }
    }

}